<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>OpenMesh: Using (custom) properties</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="logo_align.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="rwth_vci_rgb.jpg"/></td>
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">OpenMesh
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('a04338.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Using (custom) properties </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>This examples shows:</p>
<ul>
<li>How to add and remove custom properties</li>
<li>How to get and set the value of a custom property</li>
</ul>
<p>In the last example we computed the barycenter of each vertex' neighborhood and stored it in an array. It would be more convenient and less error-prone if we could store this data in the mesh and let OpenMesh manage the data. It would be even more helpful if we could attach such properties dynamically to the mesh.</p>
<p>Custom properties can be conveniently created and attached to meshes by creating an object of type <a class="el" href="a02597.html" title="This class is intended to manage the lifecycle of properties. ">OpenMesh::PropertyManager</a>. A PropertyManager manages the lifetime of the property and provides read / write access to its values.</p>
<p>You can use the typedefs VProp, HProp, EProp, FProp, and MProp in order to create a PropertyManager attached to vertices, halfedge, edges, faces and the mesh respectively. Each of these takes as template argument the type of the property value that is attached to each element (e.g., <code>int</code>, <code>double</code>, etc.).</p>
<p>We differentiate between two kinds of properties. <em>Named</em> and <em>temporary</em> properties. Temporary properties are created by just providing the constructor with a mesh on which the property should be created. These properties will be removed as soon as the PropertyManager goes out of scope. If in addition to the mesh a property name is provided, a named property will be created which will stay alive even after the PropertyManager goes out of scope. If a PropertyManager is given a name of an already existing property, it will provide read and write access to the same property.</p>
<p>Finally, an optional first parameter can be given containing a value that will be used to initialize the property for all elements if the property is freshly created (i.e. always for temporary properties, and only the first time a specific name is used).</p>
<p>Here are a few examples of how to create and access mesh properties:</p>
<div class="fragment"><div class="line"><span class="comment">// Add a temporary mesh property that stores a double value for every vertex</span></div><div class="line"><span class="keyword">auto</span> temperature = <a class="code" href="a02597.html">OpenMesh::VProp&lt;double&gt;</a>(mesh);</div><div class="line"><a class="code" href="a02241.html">OpenMesh::VertexHandle</a> vh = ...;</div><div class="line">temperature[vh] = 1.0;</div><div class="line"><span class="comment">// The temperature property will be removed from the mesh when the handle reaches the end of the scope.</span></div><div class="line"></div><div class="line"><span class="comment">// Obtain an existing property that stores a 2D vector for every halfedge</span></div><div class="line"><span class="comment">// (or create that property if it does not exist already) and initilize it with the Vector(1,1))</span></div><div class="line"><span class="keyword">auto</span> uv = <a class="code" href="a02597.html">OpenMesh::HProp&lt;OpenMesh::Vec2d&gt;</a>(mesh, <span class="stringliteral">&quot;uv&quot;</span>, <a class="code" href="a01233.html#a42e2d2e555544695c8bcbbccdc954509">OpenMesh::Vec2d</a>(1,1));</div><div class="line"><a class="code" href="a02241.html">OpenMesh::VertexHandle</a> heh = ...;</div><div class="line">std::cout &lt;&lt; temperature[heh][0] &lt;&lt; <span class="stringliteral">&quot; &quot;</span> &lt;&lt; temperature[heh][1] &lt;&lt; std::endl;</div><div class="line"></div><div class="line"><span class="comment">// Obtain an existing mesh property (or create that property if it does not exist already)</span></div><div class="line"><span class="comment">// containing a description string</span></div><div class="line"><span class="keyword">auto</span> desc = <a class="code" href="a02597.html">OpenMesh::MProp&lt;std::string&gt;</a>(mesh, <span class="stringliteral">&quot;desc&quot;</span>);</div><div class="line">*desc = <span class="stringliteral">&quot;This is a very nice mesh.&quot;</span>;</div></div><!-- fragment --> <hr/>
<h2>Code Example</h2>
<p>In this example, we will store the <code>cog</code> value (see previous example) in a vertex property instead of keeping it in a separate array. To do so, we first add a (temporary) property of the desired element type (<a class="el" href="a02241.html" title="Handle for a vertex entity. ">OpenMesh::VertexHandle</a>) and value type (<code>MyMesh::Point</code>) to the mesh:</p>
 <div class="fragment"><div class="line">      <span class="keyword">auto</span> cog = <a class="code" href="a02597.html">OpenMesh::VProp&lt;MyMesh::Point&gt;</a>(mesh);</div></div><!-- fragment --></p>
<p>Enough memory is allocated to hold as many values of <code>MyMesh::Point</code> as there are vertices. All insert and delete operations on the mesh are synchronized with the attached properties.</p>
<p>Once the property is created, we can use it to compute the centers of the neighborhood of each vertex:</p>
<p><div class="fragment"><div class="line">          <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices()) {</div><div class="line">              cog[vh] = {0,0,0};</div><div class="line">              <span class="keywordtype">int</span> valence = 0;</div><div class="line">              <span class="comment">// Iterate over all 1-ring vertices around vh</span></div><div class="line">              <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vvh : mesh.vv_range(vh)) {</div><div class="line">                  cog[vh] += mesh.point(vvh);</div><div class="line">                  ++valence;</div><div class="line">              }</div><div class="line">              cog[vh] /= valence;</div><div class="line">          }</div></div><!-- fragment --></p>
<p>Finally, we set the new position for each vertex:</p>
<p><div class="fragment"><div class="line">          <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices()) {</div><div class="line">              mesh.point(vh) = cog[vh];</div><div class="line">          }</div></div><!-- fragment --></p>
<p>Below is the complete source code:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/IO/MeshIO.hh&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/Mesh/DefaultTriMesh.hh&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/Utils/PropertyManager.hh&gt;</span></div><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;vector&gt;</span></div><div class="line"></div><div class="line"><span class="keyword">using</span> MyMesh = <a class="code" href="a02377.html">OpenMesh::TriMesh</a>;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>** argv)</div><div class="line">{</div><div class="line">    <span class="comment">// Read command line options</span></div><div class="line">    MyMesh mesh;</div><div class="line">    <span class="keywordflow">if</span> (argc != 4) {</div><div class="line">        std::cerr &lt;&lt; <span class="stringliteral">&quot;Usage: &quot;</span> &lt;&lt; argv[0] &lt;&lt; <span class="stringliteral">&quot; #iterations infile outfile&quot;</span> &lt;&lt; std::endl;</div><div class="line">        <span class="keywordflow">return</span> 1;</div><div class="line">    }</div><div class="line">    <span class="keyword">const</span> <span class="keywordtype">int</span> iterations = argv[1];</div><div class="line">    <span class="keyword">const</span> std::string infile = argv[2];</div><div class="line">    <span class="keyword">const</span> std::string outfile = argv[3];</div><div class="line">    </div><div class="line">    <span class="comment">// Read mesh file</span></div><div class="line">    <span class="keywordflow">if</span> (!<a class="code" href="a01236.html#ac417960ec28ffdd7e7003a2b1ebb2d1c">OpenMesh::IO::read_mesh</a>(mesh, infile)) {</div><div class="line">        std::cerr &lt;&lt; <span class="stringliteral">&quot;Error: Cannot read mesh from &quot;</span> &lt;&lt; infile &lt;&lt; std::endl;</div><div class="line">        <span class="keywordflow">return</span> 1;</div><div class="line">    }</div><div class="line"></div><div class="line">    {</div><div class="line">      <span class="comment">// Add a vertex property storing the computed centers of gravity</span></div><div class="line">      <span class="keyword">auto</span> cog = <a class="code" href="a02597.html">OpenMesh::VProp&lt;MyMesh::Point&gt;</a>(mesh);</div><div class="line"></div><div class="line">      <span class="comment">// Smooth the mesh several times</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; iterations; ++i) {</div><div class="line">          <span class="comment">// Iterate over all vertices to compute centers of gravity</span></div><div class="line">          <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices()) {</div><div class="line">              cog[vh] = {0,0,0};</div><div class="line">              <span class="keywordtype">int</span> valence = 0;</div><div class="line">              <span class="comment">// Iterate over all 1-ring vertices around vh</span></div><div class="line">              <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vvh : mesh.vv_range(vh)) {</div><div class="line">                  cog[vh] += mesh.point(vvh);</div><div class="line">                  ++valence;</div><div class="line">              }</div><div class="line">              cog[vh] /= valence;</div><div class="line">          }</div><div class="line">          <span class="comment">// Move all vertices to the previously computed positions</span></div><div class="line">          <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices()) {</div><div class="line">              mesh.point(vh) = cog[vh];</div><div class="line">          }</div><div class="line">      }</div><div class="line">    } <span class="comment">// The cog vertex property is removed from the mesh at the end of this scope</span></div><div class="line">    </div><div class="line">    <span class="comment">// Write mesh file</span></div><div class="line">    <span class="keywordflow">if</span> (!<a class="code" href="a01236.html#ac417960ec28ffdd7e7003a2b1ebb2d1c">OpenMesh::IO::read_mesh</a>(mesh, outfile)) {</div><div class="line">        std::cerr &lt;&lt; <span class="stringliteral">&quot;Error: Cannot write mesh to &quot;</span> &lt;&lt; outfile &lt;&lt; std::endl;</div><div class="line">        <span class="keywordflow">return</span> 1;</div><div class="line">    }</div><div class="line">}</div></div><!-- fragment --> <hr/>
<h2>Property Lifetime</h2>
<p>In the above example, we chose to use VProp without a name. This causes the created property to automatically be removed from the mesh as soon as we leave the scope of the associated handle variable <code>cog</code>.</p>
<p>If, instead, a property is desired to survive its local scope, it should be created with a name. For example:</p>
<div class="fragment"><div class="line"><span class="keyword">auto</span> face_area = <a class="code" href="a02597.html">OpenMesh::FProp&lt;double&gt;</a>(mesh, <span class="stringliteral">&quot;face_area&quot;</span>);</div></div><!-- fragment --><p>At a later time, we can access the same property by using the same name. If we want to make sure, that we access a property that has already been created earlier, we can use <a class="el" href="a02597.html#a552b239c7cfa69ce7163417787cf37bf">hasProperty()</a> to test whether a mesh has the desired property: </p><div class="fragment"><div class="line"><span class="keywordflow">if</span> (OpenMesh::hasProperty&lt;OpenMesh::FaceHandle, double&gt;(mesh, <span class="stringliteral">&quot;face_area&quot;</span>)) {</div><div class="line">    <span class="comment">// Property exists. Do something with it.</span></div><div class="line">    <span class="keyword">auto</span> valley = <a class="code" href="a02597.html">OpenMesh::FProp&lt;bool&gt;</a>(mesh, <span class="stringliteral">&quot;face_area&quot;</span>);</div><div class="line">}</div><div class="line"><span class="keywordflow">else</span> {</div><div class="line">    <span class="comment">// Property does not exist. Do something else.</span></div><div class="line">}</div></div><!-- fragment --> <hr/>
<h2>Low-Level Property API</h2>
<p>The property managers VProp, HProp, EProp, FProp and MProp are the convenient high-level interface for creating and accessing mesh properties.</p>
<p>Beneath these convenience functions, there is also a low-level property interface where handle and property lifetime must be managed manually. This interface is accessed through a mesh's add_property(), get_property(), remove_property(), and property() functions and several property handle classes (<a class="el" href="a02553.html" title="Handle representing a vertex property. ">OpenMesh::VPropHandleT</a>, <a class="el" href="a02557.html" title="Handle representing a halfedge property. ">OpenMesh::HPropHandleT</a>, <a class="el" href="a02561.html" title="Handle representing an edge property. ">OpenMesh::EPropHandleT</a>, <a class="el" href="a02565.html" title="Handle representing a face property. ">OpenMesh::FPropHandleT</a>, <a class="el" href="a02569.html" title="Handle representing a mesh property. ">OpenMesh::MPropHandleT</a>). </p><hr/>
 </div></div><!-- contents -->
</div><!-- doc-content -->
<hr>
<address>
<small>
<a href="http://www.rwth-graphics.de" style="text-decoration:none;">
</a>
Project <b>OpenMesh</b>, 
&copy;&nbsp; Computer Graphics Group, RWTH Aachen.
Documentation generated using 
<a class="el" href="http://www.doxygen.org/index.html">
<b>doxygen</b>
</a>.
</small>
</address>
</body>
</html>
